import type { DirectiveBinding } from 'vue'

const CHARS = '!<>-_[]{}—=+*^?#________'

function scrambleTo(target: HTMLElement, text: string) {
  const length = Math.max(target.innerText.length, text.length)
  const queue: Array<{ from: string; to: string; start: number; end: number; char?: string }> = []
  for (let i = 0; i < length; i++) {
    queue.push({
      from: target.innerText[i] || '',
      to: text[i] || '',
      start: Math.floor(Math.random() * 20),
      end: Math.floor(Math.random() * 20) + 10,
    })
  }
  let frame = 0
  const update = () => {
    let output = ''
    let complete = 0
    for (let i = 0; i < length; i++) {
      const q = queue[i]
      if (frame < q.start) {
        output += q.from
      } else if (frame >= q.end) {
        output += q.to
        complete++
      } else {
        if (!q.char || Math.random() < 0.28) {
          q.char = CHARS[Math.floor(Math.random() * CHARS.length)]
        }
        output += `<span class="scramble">${q.char}</span>`
      }
    }
    target.innerHTML = output
    if (complete === length) return
    requestAnimationFrame(() => {
      frame++
      update()
    })
  }
  update()
}

export default {
  mounted(el: HTMLElement, binding: DirectiveBinding<string>) {
    const original = el.innerText
    const target = binding.value || original
    el.addEventListener('mouseenter', () => scrambleTo(el, target))
  },
}


